package com.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.learning.constant.MessageConstant;
import com.learning.context.BaseContext;
import com.learning.dto.ExamPaperDTO;
import com.learning.entity.ExamPaper;
import com.learning.entity.ExamPaperQuestion;
import com.learning.entity.Knowledge;
import com.learning.entity.Question;
import com.learning.enums.DiffType;
import com.learning.enums.QuestionType;
import com.learning.exceptiom.ExamPaperErrorException;
import com.learning.exceptiom.PermissionErrorException;
import com.learning.exceptiom.QuestionNumberException;
import com.learning.exceptiom.ScoreException;
import com.learning.mapper.ExamPaperMapper;
import com.learning.mapper.ExamPaperQuestionMapper;
import com.learning.mapper.KnowledgeMapper;
import com.learning.mapper.QuestionMapper;
import com.learning.result.Result;
import com.learning.service.IExamPaperService;
import com.learning.service.IPermissionService;
import com.learning.vo.ExamPaperQuestionVO;
import com.learning.vo.ExamPaperVO;
import com.learning.vo.PermissionVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 试卷 服务实现类
 *
 * @author mhdtkc
 * @since 2024-5-29
 *
 */
@Service
public class ExamPaperServiceImpl implements IExamPaperService {

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private ExamPaperMapper examPaperMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamPaperQuestionMapper examPaperQuestionMapper;

    @Autowired
    private KnowledgeMapper knowledgeMapper;


    /**
     * 自动组卷
     * @param examPaperDTO
     */
    @Transactional
    @Override
    public void autoCreateExamPaper(ExamPaperDTO examPaperDTO) {
        // 1.获取当前教师id
        Long teacherId = BaseContext.getCurrentId();

        // 2.查询当前教师拥有的权限
        Result<PermissionVO> permissionVOResult = permissionService.queryByTeacherId(teacherId);
        PermissionVO permissionVO = permissionVOResult.getData();

        // 3.判断当前教师是否拥有组卷权限
        Boolean isSetAuth = permissionVO.getSetAuth();
        if (!isSetAuth){
            // 4.没有权限则抛出权限异常
            throw new PermissionErrorException(MessageConstant.PERMISSION_ERROR);
        }

        // 5.生成试卷表信息
        // 5.1 判断试卷总分是否小于10
        if (examPaperDTO.getTotalScore() < 10){
            // 试卷总分小于10，拋出分数异常
            throw new ScoreException(MessageConstant.EXAM_PAPER_TOTAL_SCORE_ERROR);
        }

        // 5.2 生成试卷表信息
        ExamPaper examPaper = BeanUtil.copyProperties(examPaperDTO, ExamPaper.class);
        examPaper.setTeacherId(teacherId);
        examPaper.setCreateTime(LocalDateTime.now());
        examPaper.setUpdateTime(LocalDateTime.now());

        // 6.插入试卷表
        examPaperMapper.insert(examPaper);
        Long examPaperId = examPaper.getId();

        // 7.试卷总分
        Short totalScore = examPaperDTO.getTotalScore();

        // 8.选择题
        // 8.1 前端要求的选择题数量
        Short selectQuestionNumber = examPaperDTO.getSelectQuestionNumber();
        if (selectQuestionNumber < 1){
            // 前端要求的题目数量小于1，抛出题目数量异常
            throw new QuestionNumberException(MessageConstant.QUESTION_NUMBER_ERROR);
        }

        // 8.2 从题库选出选择题
        List<Question> selectQuestionList = this.createQuestion(
                selectQuestionNumber,
                examPaperDTO.getDifficulty(),
                QuestionType.CHOICE);

        // 8.3 算出每道选择题的分值
        float selectQuestionScore = getQuestionScore(totalScore, 0.4f, selectQuestionList);

        // 8.4 向试卷题目关系表插入数据
        for (Question question : selectQuestionList) {
            ExamPaperQuestion examPaperQuestion = new ExamPaperQuestion();
            // 试卷id
            examPaperQuestion.setExamPaperId(examPaperId);
            // 题目id
            examPaperQuestion.setQuestionId(question.getId());
            // 题目分值
            examPaperQuestion.setQuestionScore(selectQuestionScore);
            // 插入数据
            examPaperQuestionMapper.insert(examPaperQuestion);
        }



        // 9.填空题
        // 9.1 前端要求的填空题数量
        Short blackfillQuestionNumber = examPaperDTO.getBlackfillQuestionNumber();
        if(blackfillQuestionNumber < 1){
            // 前端要求的题目数量小于1，抛出题目数量异常
            throw new QuestionNumberException(MessageConstant.QUESTION_NUMBER_ERROR);
        }


        // 9.2 从题库选出填空题
        List<Question> blackfillQuestionList = this.createQuestion(
                blackfillQuestionNumber,
                examPaperDTO.getDifficulty(),
                QuestionType.GAP);

        // 9.3 算出每道填空题的分值
        float blackfillQuestionScore = getQuestionScore(totalScore, 0.2f, blackfillQuestionList);

        // 9.4 向试卷题目关系表插入数据
        for (Question question : blackfillQuestionList) {
            ExamPaperQuestion examPaperQuestion = new ExamPaperQuestion();
            // 试卷id
            examPaperQuestion.setExamPaperId(examPaperId);
            // 题目id
            examPaperQuestion.setQuestionId(question.getId());
            // 题目分值
            examPaperQuestion.setQuestionScore(blackfillQuestionScore);
            // 插入数据
            examPaperQuestionMapper.insert(examPaperQuestion);
        }


        // 10.主观题
        // 10.1 前端要求的主观题数量
        Short subjectiveQuestionNumber = examPaperDTO.getSubjectiveQuestionNumber();
        if(subjectiveQuestionNumber < 1){
            // 前端要求的题目数量小于1，抛出题目数量异常
            throw new QuestionNumberException(MessageConstant.QUESTION_NUMBER_ERROR);
        }


        // 10.2从题库选出主观题
        List<Question> subjectiveQuestionList = this.createQuestion(
                subjectiveQuestionNumber,
                examPaperDTO.getDifficulty(),
                QuestionType.SUBJECTIVE);

        // 10.3 算出每道主观题的分值
        float subjectiveQuestionScore = getQuestionScore(totalScore, 0.4f, subjectiveQuestionList);

        // 10.4 向试卷题目关系表插入数据
        for (Question question : subjectiveQuestionList) {
            ExamPaperQuestion examPaperQuestion = new ExamPaperQuestion();
            // 试卷id
            examPaperQuestion.setExamPaperId(examPaperId);
            // 题目id
            examPaperQuestion.setQuestionId(question.getId());
            // 题目分值
            examPaperQuestion.setQuestionScore(subjectiveQuestionScore);
            // 插入数据
            examPaperQuestionMapper.insert(examPaperQuestion);
        }

    }


    /**
     * 算出每个题型一道题目的分值
     * @param totalScore
     * @param rate
     * @param questionList
     * @return
     */
    private float getQuestionScore(Short totalScore, float rate, List<Question> questionList) {
        // 1.根据试卷总分totalScore和当前题型的占比rate算出当前题型的总分
        float curTypeTotalScore = totalScore * rate;

        // 2.每道题的分值
        float questionScore = curTypeTotalScore / questionList.size();

        return questionScore;
    }


    /**
     * 根据题目数量、试卷难度、题目类型 随机组成题目
     * @param questionNumber
     * @param questionType
     * @return
     */
    private List<Question> createQuestion(Short questionNumber, DiffType examPaperDiff, QuestionType questionType) {
        Question question = new Question();
        // 1 题目类型
        question.setType(questionType);
        // 2 试卷难度
        question.setDifficulty(examPaperDiff);
        // 3 符合条件的全部题目
        List<Question> questionBaseList = questionMapper.query(question);
        // 4 题库数量
        int questionBaseNumber = questionBaseList.size();
        // 前端要求的数量 -> questionNumber
        // 5 判断题库数量是否小于前端要求的数量
        if (questionBaseNumber < questionNumber) {
            switch(questionType){
                case CHOICE:
                    throw new ExamPaperErrorException(MessageConstant.SELECT_QUESTION_NUMBER_ERROR);
                case GAP:
                    throw new ExamPaperErrorException(MessageConstant.BLACKFILL_QUESTION_NUMBER_ERROR);
                case SUBJECTIVE:
                    throw  new ExamPaperErrorException(MessageConstant.SUBJECTIVE_QUESTION_NUMBER_ERROR);
            }
        }

        Random random = new Random();
        // 6 选出前端指定的数量题目
        List<Question> result = new ArrayList<>();
        while (result.size() < questionNumber) {
            // 6.1 随机选取
            int index = random.nextInt(questionBaseNumber);
            Question resultQuestion = questionBaseList.get(index);

            // 6.2 判断选取的题目是否在在最终的集合
            boolean isContains = result.contains(resultQuestion);
            if (!isContains) {
                // 6.3 选取的题目不在最终集合，将选取的题目加入最终的集合
                result.add(resultQuestion);
            }
        }

        return result;
    }


    /**
     * 手动组卷初始化
     * @return 初始化试卷id
     */
    @Override
    public Long manualCreateExamPaper() {
        // 1.获取当前教师id
        Long teacherId = BaseContext.getCurrentId();

        // 2.查询当前教师拥有的权限
        Result<PermissionVO> permissionVOResult = permissionService.queryByTeacherId(teacherId);
        PermissionVO permissionVO = permissionVOResult.getData();

        // 3.判断当前教师是否拥有组卷权限
        Boolean isSetAuth = permissionVO.getSetAuth();
        if (!isSetAuth){
            // 4.没有权限则抛出权限异常
            throw new PermissionErrorException(MessageConstant.PERMISSION_ERROR);
        }

        // 5.初始化试卷数据
        ExamPaper examPaper = new ExamPaper();
        // 5.1 手动组卷设难度为中等，置为2
        examPaper.setDifficulty(DiffType.MEDIUM);
        // 5.2 初始化试卷的选择题数量为0
        examPaper.setSelectQuestionNumber((short) 0);
        // 5.3 初始化试卷的选择题数量为0
        examPaper.setBlackfillQuestionNumber((short) 0);
        // 5.4 初始化试卷的主观题数量为0
        examPaper.setSubjectiveQuestionNumber((short) 0);
        // 5.5 初始化试卷的总分为0
        examPaper.setTotalScore((short) 0);
        // 5.6 创建此试卷的教师id
        examPaper.setTeacherId(teacherId);
        // 5.7 生成试卷的时间
        examPaper.setCreateTime(LocalDateTime.now());
        // 5.8 更新试卷的时间
        examPaper.setUpdateTime(LocalDateTime.now());

        // 6.向试卷表exam_paper插入一条数据
        examPaperMapper.insert(examPaper);

        // 7.返回新建的试卷id
        return examPaper.getId();

    }


    /**
     * 查询所有试卷信息
     * @return
     */
    @Override
    public List<ExamPaperVO> queryAll() {
        // 1.查询试卷表exam_paper的全部数据
        List<ExamPaper> examPaperList = examPaperMapper.selectAll();

        // 2.当数据库没有任何试卷时，抛出查询全部试卷失败异常
        if(CollectionUtil.isEmpty(examPaperList)){
            throw new ExamPaperErrorException(MessageConstant.QUERY_ALL_EXAM_PAPER_FAILED);
        }

        List<ExamPaperVO> list = new ArrayList<>();
        // 3.遍历每张试卷
        for (ExamPaper examPaper : examPaperList) {
            // 4.试卷id
            Long examPaperId = examPaper.getId();
            // 5.查询试卷所有信息
            ExamPaperVO examPaperVO = this.queryByExamPaperId(examPaperId);
            list.add(examPaperVO);
        }

        return list;
    }


    /**
     * 根据试卷id查询试卷信息
     * @param examPaperId
     * @return
     */
    @Override
    public ExamPaperVO queryByExamPaperId(Long examPaperId) {

        // 1.根试卷id查询exam_paper试卷表
        ExamPaper examPaper = examPaperMapper.selectById(examPaperId);

        // 2.当查询不到试卷时，抛出查询试卷失败异常
        if(examPaper == null){
            throw new ExamPaperErrorException(MessageConstant.QUERY_EXAM_PAPER_FAILED);
        }

        // 3.将试卷实体对象ExamPaper复制到ExamPaperVO对象
        ExamPaperVO examPaperVO = BeanUtil.copyProperties(examPaper, ExamPaperVO.class);
        examPaperVO.setExamPaperId(examPaperId);

        // 4.获取一张试卷的全部题目
        List<ExamPaperQuestion> examPaperQuestionList =
                examPaperQuestionMapper.selectByExamPaperId(examPaperId);

        // 5.试卷中没有题目
        if (CollectionUtil.isEmpty(examPaperQuestionList)){
            // 将试卷的题目列表置为空
            examPaperVO.setExamPaperQuestionList(null);
            return examPaperVO;
        }

        // 6.一张试卷的全部题目详细信息
        List<ExamPaperQuestionVO> examPaperQuestionVOList = new ArrayList<>();

        // 7.组成试卷的题目信息
        for (ExamPaperQuestion examPaperQuestion : examPaperQuestionList) {
            ExamPaperQuestionVO examPaperQuestionVO = new ExamPaperQuestionVO();

            // 7.1 题目id
            Long questionId = examPaperQuestion.getQuestionId();
            examPaperQuestionVO.setQuestionId(questionId);

            // 7.2 题目分数
            float questionScore = examPaperQuestion.getQuestionScore();
            examPaperQuestionVO.setQuestionScore(questionScore);

            // 7.3 根据题目id去题目表查询题目
            Question question = questionMapper.queryById(questionId);

            // 7.4 题目类型
            examPaperQuestionVO.setQuestionType(question.getType());

            // 7.5 题目难易度
            examPaperQuestionVO.setDifficulty(question.getDifficulty());

            // 7.6 题目内容
            examPaperQuestionVO.setQuestionContent(question.getQuestionContent());

            // 7.7 根据题目id查询知识点表的知识点
            Knowledge knowledge = knowledgeMapper.queryByQuestionId(questionId);

            // 7.8 知识点内容
            examPaperQuestionVO.setKnowledgeContent(knowledge.getKnowledgeContent());

            // 7.9 将一道题目对象加入列表试卷的题目列表
            examPaperQuestionVOList.add(examPaperQuestionVO);
        }

        // 8.一张试卷的全部题目列表
        examPaperVO.setExamPaperQuestionList(examPaperQuestionVOList);

       return examPaperVO;
    }


    /**
     * 根据试卷id删除试卷
     * @param examPaperId
     */
    @Transactional
    @Override
    public void deleteByExamPaperId(Long examPaperId) {
        // 1.根据试卷id从试卷exam_paper表删除试卷
        examPaperMapper.deleteById(examPaperId);

        // 2.根据试卷id从试卷题目关系exam_paper_question表删除试卷的题目
        examPaperQuestionMapper.deleteByExamPaperId(examPaperId);
    }

}
